package repository

import (
	"context"
	"database/sql"
	"fmt"
	"gitee.com/DonHz/basic-go/webook/internal/domain"
	"gitee.com/DonHz/basic-go/webook/internal/repository/cache"
	"gitee.com/DonHz/basic-go/webook/internal/repository/dao"
	"time"
)

var (
	ErrUserDuplicate = dao.ErrUserDuplicate
	ErrUserNotFound  = dao.ErrUserNotFound
)

type UserRepository interface {
	Create(ctx context.Context, u domain.User) error
	FindByEmail(ctx context.Context, email string) (domain.User, error)
	FindByPhone(ctx context.Context, phone string) (domain.User, error)
	FindById(ctx context.Context, Id int64) (domain.User, error)
	// 微信查找，可以用UnionID和OpenID
	FindByWechat(ctx context.Context, wechatInfo domain.WechatInfo) (domain.User, error)
	UpdateNonZeroFields(ctx context.Context, user domain.User) error
}

type CachedUserRepository struct {
	dao   dao.UserDAO
	cache cache.UserCache
}

func NewUserRepository(dao dao.UserDAO, cache cache.UserCache) UserRepository {
	return &CachedUserRepository{
		dao:   dao,
		cache: cache,
	}
}

func (r *CachedUserRepository) Create(ctx context.Context, u domain.User) error {
	return r.dao.Insert(ctx, r.domainToEntity(u))
}

func (r *CachedUserRepository) FindByEmail(ctx context.Context, email string) (domain.User, error) {
	u, err := r.dao.FindByEmail(ctx, email)
	if err != nil {
		return domain.User{}, err
	}
	return r.entityToDomain(u), nil
}

func (r *CachedUserRepository) FindByPhone(ctx context.Context, phone string) (domain.User, error) {
	u, err := r.dao.FindByPhone(ctx, phone)
	if err != nil {
		return domain.User{}, err
	}
	return r.entityToDomain(u), nil
}

func (r *CachedUserRepository) FindById(ctx context.Context, Id int64) (domain.User, error) {
	// 分三种情况
	// 1、缓存里面有数据
	//u, err:= r.cache.GetUser(ctx, Id)
	//if err == nil{
	//	return u, nil
	//}
	// 2、缓存里面没数据
	// 去数据库里面找
	ue, err := r.dao.FindById(ctx, Id)
	fmt.Println("user_FindById: ", ue)
	if err != nil {
		return domain.User{}, err
	}


	u := r.entityToDomain(ue)
	fmt.Println("entityToDomain: ", u)
	err = r.cache.SetUser(ctx, u)
	// 3、缓存出错，不知道有没有数据
	// 缓存设置失败
	if err!=nil {
		// 打日志，做监控
		return domain.User{}, err
	}
	return u, nil
}
func (r *CachedUserRepository) FindByWechat(ctx context.Context,
	wechatInfo domain.WechatInfo) (domain.User, error){
	ue, err := r.dao.FindByWechat(ctx, wechatInfo)
	if err != nil {
		return domain.User{}, err
	}
	u := r.entityToDomain(ue)
	err = r.cache.SetUser(ctx, u)
	// 3、缓存出错，不知道有没有数据
	// 缓存设置失败
	if err!=nil {
		// 打日志，做监控
		return domain.User{}, err
	}
	return u, nil
}



func (r *CachedUserRepository) UpdateNonZeroFields(ctx context.Context, user domain.User) error {
	return r.dao.UpdateById(ctx, dao.User{
		Id:       user.Id,
		Nickname: user.Nickname,
		Birthday: user.Birthday.Unix(),
		AboutMe:  user.AboutMe,
	})
}

func (r *CachedUserRepository) domainToEntity(u domain.User) dao.User{
	return dao.User{
		Id: u.Id,
		Email: sql.NullString{
			String: u.Email,
			Valid: u.Email!="",
		},
		Password: u.Password,
		Phone: sql.NullString{
			String: u.Phone,
			Valid: u.Phone!="",
		},
		WechatOpenID: sql.NullString{
			String: u.WechatInfo.OpenID,
			Valid: u.WechatInfo.OpenID!="",
		},
		WechatUnionID: sql.NullString{
			String: u.WechatInfo.UnionID,
			Valid: u.WechatInfo.UnionID!="",
		},

		CreateTime: u.Ctime.UnixMilli(),
	}
}

func (r *CachedUserRepository) entityToDomain(u dao.User) domain.User{
	return domain.User{
		Id: u.Id,
		Email: u.Email.String,
		Password: u.Password,
		Phone: u.Phone.String,
		Nickname: u.Nickname,
		AboutMe: u.AboutMe,
		WechatInfo: domain.WechatInfo{
			OpenID: u.WechatOpenID.String,
			UnionID: u.WechatUnionID.String,
		},
		Ctime:time.UnixMilli(u.CreateTime),
	}
}